<script setup lang="ts">
import { cloneDeep } from "lodash";
import { MESSAGE_JSON } from "@/schema/interview";
import ChatBubble from "@/components/common/ChatBubble.vue";
import { storeToRefs } from "pinia";
import appStore from "@/store";
import { IMessage } from "@/interface/interviewInfo";
import {Action, ElMessage, ElMessageBox} from "element-plus";
import { getAudio } from "@/http/m_api/ttsService";
import { AVMedia } from "vue-audio-visual";
import {
  Expand,
  VideoCamera,
  VideoPause,
  VideoPlay,
  Fold,
  Close,
  Microphone,
  Refresh,
  Setting,
  List,
  ChatDotRound,
  Monitor,
  PhoneFilled
} from "@element-plus/icons-vue";
import { finishInterview, postAudioUrl, pushAIMessage, receiveAIMessage } from "@/http/m_api/interview";
import router from "@/router";
import { ref, onMounted, onUnmounted, watch, nextTick, shallowRef, computed } from 'vue';
import { useSpeechRecognition } from '@vueuse/core';
import {gsvi_audio_path_pre} from "@/assets/ts/constant";

const status = ref(0);
const { PushMessage, ResetStore } = appStore.useInterviewJsonStore;
const { interviewNewStore } = storeToRefs(appStore.useInterviewJsonStore);

// Animation state
const fadeIn = ref(false);

onMounted(() => {
  setTimeout(() => {
    fadeIn.value = true;
  }, 100);
  PlayAudioQueue();
  if (interviewNewStore.value.Settings.cameraPermit) {
    cameraTr();
  }
  audioRef.value.addEventListener('play', () => {
    paused.value = false;
  });
  audioRef.value.addEventListener('pause', () => {
    paused.value = true;
  });
});

// Theme and styling
const bubbleStyle = ref('light');
const bubbleStyleSelf = ref('default');
const customAiColor = ref(['#4f4f4f', '#ffffff']);
const customSelfColor = ref(['#95EC69', '#000000']);

const statusMessage = ['等待您的回答', 'AI思考中...', '正在提问'];
const statusColors = ['#67c23a', '#e6a23c', '#409eff'];

// Speech recognition
const speech = useSpeechRecognition({ lang: shallowRef('zh-CN'), continuous: true });
const { isListening, isSupported, stop, result } = speech;

watch(speech.result, () => {
  inputMsg.value = tempMsg.value + speech.result.value;
});
watch(speech.isListening, (newVal, oldVal) => {
  if (oldVal && audioInputting.value) {
    try {
      Record(false);
    } catch (e) {}
    ElMessage({ type: 'warning', message: '长时间未识别到有效结果，已暂时结束录音' });
  }
});

// Audio and video refs
const audioRef = ref();
const videoRef = ref();
const microphoneRef = ref();
const container = ref();

// State management
const drawer = ref(false);
const settingsDrawer = ref(false);
const inputMsg = ref('');
const audioInputting = ref(false);
const finished = ref(false);
const cameraOpen = ref(false);
const paused = ref(false);
const currentMessageId = ref(0);
const tempMsg = ref("");

// Media streams
const currentMicrophoneStream = ref();
const currentCameraStream = ref();

// Audio queue management
const AudioMessageQueue = ref<Array<IMessage>>([]);
const AudioReadyQueue = ref<Array<IReadyAudio>>([]);
const currentAudio = ref();
const playingAudio = ref(false);

interface IReadyAudio {
  audio_url: string;
  message: IMessage;
}

// Computed properties
const isRecording = computed(() => audioInputting.value || isListening.value);
const canSend = computed(() => status.value === 0 && inputMsg.value.trim() !== '');
const totalAudioItems = computed(() =>
    (currentAudio.value ? 1 : 0) + AudioReadyQueue.value.length + AudioMessageQueue.value.length
);

const getReferenceMessage = (id: number) => {
  if (id < interviewNewStore.value.Messages.length) {
    return interviewNewStore.value.Messages[id];
  } else {
    return '';
  }
};

const pushAudio = (message: IMessage) => {
  const result = AudioMessageQueue.value.find(item => item.id === message.id);
  if(!result) {
    ElMessage.warning('消息正在处理队列中，请稍后！')
    return;
  }
  if (message.id === currentMessageId.value){
    ElMessage.warning('消息正在生成中，请稍后！')
    return;
  }
  AudioMessageQueue.value.push(message);
  if (AudioMessageQueue.value.length === 1) {
    ProcessAudio();
  }
};

const pushMessages = (content: string) => {
  let message = cloneDeep(MESSAGE_JSON);
  message.id = interviewNewStore.value.Messages.length;
  message.type = false;
  message.content = content;
  message.hideContent = false;
  message.showAsMarkdown = true;
  message.audio_url = '';
  message.time = new Date();
  PushMessage(message);
  nextTick(() => {
    ProcessScroll();
  });
  receiveMessages(content);
};

const handleStreamData = (chunk: string) => {
  const regex = /{.*?}/g;
  const matches = chunk.match(regex);
  if (matches) {
    matches.forEach((match) => {
      try {
        const obj = JSON.parse(match);
        if (obj.isFirst) {
          status.value = 2;
        }
        if (obj.content) {
          for (let i = 0; i < obj.content.length; i++) {
            interviewNewStore.value.Messages[currentMessageId.value].content += obj.content[i];
          }
        }
      } catch (error) {
        console.error(`无法解析的 JSON: ${match}`);
      }
    });
  }
};

const receiveMessages = (content: string) => {
  let message = cloneDeep(MESSAGE_JSON);
  message.id = interviewNewStore.value.Messages.length;
  message.type = true;
  message.hideContent = false;
  message.content = '';
  message.showAsMarkdown = true;
  message.audio_url = '';
  message.time = new Date();
  PushMessage(message);
  currentMessageId.value = message.id;
  status.value = 1;

  receiveAIMessage(
      {
        interviewId: interviewNewStore.value.id,
        content: content,
        hideContent: false,
        showAsMarkdown: true,
        referenceId: -1,
        audioUrl: '',
        again: false
      },
      handleStreamData,
      (error: any) => {
        ElMessage.error('出现错误，请重试');
        status.value = 0;
      },
      () => {
        status.value = 0;
        if (interviewNewStore.value.Messages[currentMessageId.value].content.search('<!-- INTERVIEW_END -->') !== -1) {
          SetFinish();
        }
        pushAudio(message)
      }
  );
};

const SetFinish = () => {
  ElMessage.success("面试官发起终止面试，您可以正常结束面试");
  finished.value = true;
};

const clickFinish = () => {
  if (finished.value) {
    ElMessageBox.confirm(
        '面试官已发起终止，您可正常结束',
        '结束面试',
        {
          confirmButtonText: '结束面试',
          cancelButtonText: '取消',
          type: 'success',
        }
    ).then(async () => {
      const data = await finishInterview(interviewNewStore.value.id);
      if (data.code === 0) {
        ElMessage.success('提交成功！');
        router.go(0)
      }
    });
  } else {
    ElMessageBox.confirm(
        '面试官尚未发起终止，您是否要提前终止？',
        '提前结束',
        {
          confirmButtonText: '提前终止',
          cancelButtonText: '暂时离开',
          type: 'warning',
          distinguishCancelAndClose: true
        }
    ).then(async () => {
      const data = await finishInterview(interviewNewStore.value.id);
      if (data.code === 0) {
        ElMessage.success('提交成功！');
        router.go(0)
      }
    }).catch((action: Action)=>{
      if(action === 'cancel'){
        ElMessage.success('提交成功！');
        router.go(0)
      }

    })
  }
};

async function fetchAudio(message: IMessage): Promise<string> {
  try {
    if (message.audio_url && message.audio_url !== '') {
      return message.audio_url;
    }
    const data = await getAudio(message.content);

    if (!data) {
      ElMessage({ type: "error", message: '数据异常！' });
      throw new Error('Invalid data received from getAudio');
    }

    let audioUrl;

    if (data instanceof ArrayBuffer) {
      const audioBlob = new Blob([data], { type: 'audio/mpeg' });
      audioUrl = URL.createObjectURL(audioBlob);
    } else if (data.audio_url) {
      audioUrl = data.audio_url.replace('http://127.0.0.1:9874', gsvi_audio_path_pre);
      message.audio_url = audioUrl;
      postAudioUrl({
        interviewId: interviewNewStore.value.id,
        messageId: message.id,
        again: false,
        hideContent: message.hideContent,
        showAsMarkdown: message.showAsMarkdown,
        audioUrl: audioUrl
      });
    } else {
      ElMessage({ type: "error", message: '音频数据格式不支持！' });
      throw new Error('Unsupported audio data format');
    }

    return audioUrl;
  } catch (error) {
    console.error('Error fetching audio:', error);
    ElMessage({ type: "error", message: "合成失败，请稍后再试" });
    throw error;
  }
}

async function ProcessAudio() {
  while (AudioMessageQueue.value.length > 0) {
    let message = AudioMessageQueue.value[0];
    if (message) {
      try {
        const audioUrl = await fetchAudio(message);
        AudioReadyQueue.value.push({ audio_url: audioUrl, message: message });
      } catch (error) {
        console.error('音频获取有误：', error);
      } finally {
        AudioMessageQueue.value.shift();
      }
    }
  }
}

async function PlayAudioQueue() {
  while (true) {
    if (AudioReadyQueue.value.length > 0) {
      if (playingAudio.value) {
        await new Promise<void>((resolve) => {
          const interval = setInterval(() => {
            if (!playingAudio.value || audioRef.value.readyState === 0 || audioRef.value?.ended) {
              currentAudio.value = null;
              clearInterval(interval);
              playingAudio.value = false;
              resolve();
            }
          }, 500);
        });
      } else {
        const item = AudioReadyQueue.value.shift()!;
        currentAudio.value = item;
        if (audioRef.value) {
          audioRef.value.src = item.audio_url;
          audioRef.value.play();
          playingAudio.value = true;
        } else {
          ElMessage({ type: "error", message: '播放器出错！' });
          return;
        }
      }
    } else {
      if (audioRef.value?.ended) {
        currentAudio.value = null;
      }
      await new Promise<void>((resolve) => {
        setTimeout(() => {
          resolve();
        }, 500);
      });
    }
  }
}

const stopStream = (stream: MediaStream) => {
  if (stream) {
    const tracks = stream.getTracks();
    tracks.forEach((track: any) => {
      track.stop();
    });
  }
};
const cooldown = ref(false)

const Record = async (force: boolean = true) => {
  if (audioInputting.value || !force) {
    audioInputting.value = false;
    cooldown.value = true;
    setTimeout(()=>{
      cooldown.value = false
    }, 3000)
    if (currentMicrophoneStream.value) {
      stopStream(currentMicrophoneStream.value);
      currentMicrophoneStream.value = null;
    }
    speech.stop();
  }
  else {
    if(cooldown.value){
      ElMessage.warning("冷却中，请稍后")
      return
    }
    speech.result.value = '';
    tempMsg.value = inputMsg.value;
    if(!isListening.value){
      speech.start();
    }

    audioInputting.value = true;

    if (currentMicrophoneStream.value) {
      stopStream(currentMicrophoneStream.value);
    }
    currentMicrophoneStream.value = null;
    let option: any;
    if (interviewNewStore.value.Settings.microphoneChoice) {
      option = { deviceId: interviewNewStore.value.Settings.microphoneChoice.deviceId };
    } else {
      option = true;
    }
    await navigator.mediaDevices.getUserMedia({
      audio: option
    }).then((stream) => {
      currentMicrophoneStream.value = stream;
    }).catch((reason) => {
      ElMessage({ type: "error", message: reason });
    });
  }
};

const cameraTr = async () => {
  if (cameraOpen.value) {
    cameraOpen.value = false;
    if (currentCameraStream.value) {
      stopStream(currentCameraStream.value);
    }
  } else {
    cameraOpen.value = true;
    if (currentCameraStream.value) {
      stopStream(currentCameraStream.value);
    }
    currentCameraStream.value = null;
    let option: any;
    if (interviewNewStore.value.Settings.cameraChoice) {
      option = { deviceId: interviewNewStore.value.Settings.cameraChoice.deviceId };
    } else {
      option = true;
    }
    await navigator.mediaDevices.getUserMedia({
      video: option
    }).then((stream) => {
      currentCameraStream.value = stream;
      if (videoRef.value) {
        videoRef.value.srcObject = currentCameraStream.value;
      } else {
        ElMessage({ type: "error", message: '视频组件加载失败' });
        stopStream(currentCameraStream.value);
      }
    }).catch((reason) => {
      ElMessage({ type: "error", message: reason });
    });
  }
};

const send = () => {
  if (status.value !== 0) {
    ElMessage({ type: "error", message: '当前无法发送，请等待面试官提问结束' });
    return;
  } else {
    if (inputMsg.value === '') {
      ElMessage({ type: "error", message: '请输入内容' });
      return;
    }
    pushMessages(inputMsg.value);
    inputMsg.value = '';
  }
};

const ProcessScroll = () => {
  if (container.value) {
    container.value.scrollTop = container.value.scrollHeight;
  }
};

const expandAll = () => {
  for (let i = 0; i < interviewNewStore.value.Messages.length; i++) {
    interviewNewStore.value.Messages[i].hideContent = false;
  }
};

const foldAll = () => {
  for (let i = 0; i < interviewNewStore.value.Messages.length; i++) {
    interviewNewStore.value.Messages[i].hideContent = true;
  }
};

const playAll = () => {
  for (let item of interviewNewStore.value.Messages) {
    if (item.type) {
      pushAudio(item);
    }
  }
};

onUnmounted(() => {
  if (currentCameraStream.value) {
    stopStream(currentCameraStream.value);
  }
  if (currentMicrophoneStream.value) {
    stopStream(currentMicrophoneStream.value);
  }
});

const testAudio = require('@/assets/audio/testAudio.wav');
</script>

<template>
  <div class="interview-container" :class="{ 'fade-in': fadeIn }">
    <!-- Floating Action Buttons -->
    <div class="floating-actions">
      <el-tooltip content="折叠所有消息" placement="right">
        <el-button type="primary" circle @click="foldAll" class="action-btn" style="margin-left: 12px">
          <el-icon><Fold /></el-icon>
        </el-button>
      </el-tooltip>
      <el-tooltip content="展开所有消息" placement="right">
        <el-button type="success" circle @click="expandAll" class="action-btn">
          <el-icon><Expand /></el-icon>
        </el-button>
      </el-tooltip>
      <el-tooltip content="播放所有AI消息" placement="right">
        <el-button type="warning" circle @click="playAll" class="action-btn">
          <el-icon><VideoPlay /></el-icon>
        </el-button>
      </el-tooltip>
      <el-tooltip content="播放列表" placement="right">
        <el-button type="info" circle @click="drawer = true" class="action-btn">
          <el-icon><List /></el-icon>
          <el-badge v-if="totalAudioItems > 0" :value="totalAudioItems" class="audio-badge" />
        </el-button>
      </el-tooltip>
    </div>

    <!-- Main Interface -->
    <div class="main-interface">
      <!-- Chat Section -->
      <div class="chat-section">
        <!-- Status Header -->
        <div class="status-header">
          <div class="status-indicator">
            <div class="status-dot" :style="{ backgroundColor: statusColors[status] }"></div>
            <span class="status-text">{{ statusMessage[status] }}</span>
          </div>
          <div class="header-actions">
            <el-button size="small" circle @click="settingsDrawer = true">
              <el-icon><Setting /></el-icon>
            </el-button>
          </div>
        </div>

        <!-- Chat Container -->
        <div class="chat-container" ref="container">
          <chat-bubble
              v-for="(msg, index) in interviewNewStore.Messages"
              :key="index"
              :message="msg"
              :bubble-style="bubbleStyle"
              :bubble-self-style="bubbleStyleSelf"
              :custom-ai-color="customAiColor"
              :custom-self-color="customSelfColor"
              :show-play="msg.type"
              @play-audio="pushAudio(msg)"
              class="chat-message"
          >
            <template #reference v-if="msg.referenceId && msg.referenceId !== -1">
              {{ getReferenceMessage(msg.referenceId) }}
            </template>
          </chat-bubble>
        </div>
      </div>

      <!-- Control Panel -->
      <div class="control-panel">
        <!-- Video Preview -->
        <div class="video-section" v-if="interviewNewStore.Settings.cameraPermit">
          <div class="video-header">
            <span class="video-title">视频预览</span>
            <el-button
                size="small"
                :type="cameraOpen ? 'danger' : 'primary'"
                @click="cameraTr"
                class="camera-toggle"
            >
              <el-icon><VideoCamera /></el-icon>
              {{ cameraOpen ? '关闭' : '开启' }}
            </el-button>
          </div>
          <div class="video-wrapper">
            <video
                ref="videoRef"
                autoplay
                playsinline
                class="video-preview"
                :class="{ 'inactive': !cameraOpen }"
            />
            <div v-if="!cameraOpen" class="video-overlay">
              <el-icon class="overlay-icon"><VideoCamera /></el-icon>
              <span>摄像头已关闭</span>
            </div>
          </div>
        </div>

        <!-- Input Section -->
        <div class="input-section">
          <div class="input-header">
            <span class="input-title">消息输入</span>
            <div class="input-actions">
              <el-button
                  v-if="interviewNewStore.Settings.microphonePermit"
                  size="small"
                  :type="isRecording ? 'danger' : 'success'"
                  @click="Record"
                  :disabled="!audioInputting && isListening"
                  class="record-btn"
              >
                <el-icon>
                  <Microphone v-if="!isRecording" />
                  <svg v-else xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-mic-fill" viewBox="0 0 16 16">
                    <path d="M5 3a3 3 0 0 1 6 0v5a3 3 0 0 1-6 0z"/>
                    <path d="M3.5 6.5A.5.5 0 0 1 4 7v1a4 4 0 0 0 8 0V7a.5.5 0 0 1 1 0v1a5 5 0 0 1-4.5 4.975V15h3a.5.5 0 0 1 0 1h-7a.5.5 0 0 1 0-1h3v-2.025A5 5 0 0 1 3 8V7a.5.5 0 0 1 .5-.5"/>
                  </svg>
                </el-icon>
                {{ isRecording ? '停止录音' : '开始录音' }}
              </el-button>
            </div>
          </div>

          <el-input
              type="textarea"
              v-model="inputMsg"
              placeholder="请输入您的回答..."
              resize="none"
              :rows="interviewNewStore.Settings.cameraPermit ? 8 : 12"
              :disabled="isListening || audioInputting"
              class="message-input"
              @keydown.ctrl.enter="send"
          />

          <div class="input-controls">
            <el-button
                type="primary"
                @click="send"
                :disabled="!canSend"
                class="send-btn"
            >
              <el-icon>
                <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-send" viewBox="0 0 16 16">
                  <path d="M15.854.146a.5.5 0 0 1 .11.54l-5.819 14.547a.75.75 0 0 1-1.329.124l-3.178-4.995L.643 7.184a.75.75 0 0 1 .124-1.33L15.314.037a.5.5 0 0 1 .54.11ZM6.636 10.07l2.761 4.338L14.13 2.576zm6.787-8.201L1.591 6.602l4.339 2.76z"/>
                </svg>
              </el-icon>
              {{ status === 0 ? '发送消息' : '请等待...' }}
            </el-button>
            <el-button
                type="danger"
                @click="clickFinish"
                class="finish-btn"
            >
              <el-icon><PhoneFilled /></el-icon>
              结束面试
            </el-button>
          </div>
        </div>

        <!-- Audio Visualizer -->
        <div v-if="interviewNewStore.Settings.microphonePermit" class="audio-visualizer">
          <a-v-media
              ref="microphoneRef"
              type="frequ"
              frequ-direction="mo"
              :media="currentMicrophoneStream"
              class="visualizer-component"
          />
        </div>
      </div>
    </div>

    <!-- Audio Player (Hidden) -->
    <audio ref="audioRef" :src="testAudio" style="display: none;" />

    <!-- Settings Drawer -->
    <el-drawer
        v-model="settingsDrawer"
        title="界面设置"
        direction="rtl"
        size="350px"
        class="settings-drawer"
    >
      <div class="settings-content">
        <div class="setting-group">
          <h4 class="group-title">AI消息主题</h4>
          <el-select v-model="bubbleStyle" class="theme-select">
            <el-option label="浅色主题" value="light" />
            <el-option label="深色主题" value="dark" />
            <el-option label="自定义" value="custom" />
          </el-select>
          <div v-if="bubbleStyle === 'custom'" class="color-pickers">
            <div class="color-item">
              <span>背景色</span>
              <el-color-picker v-model="customAiColor[0]" show-alpha />
            </div>
            <div class="color-item">
              <span>文字色</span>
              <el-color-picker v-model="customAiColor[1]" />
            </div>
          </div>
        </div>

        <div class="setting-group">
          <h4 class="group-title">我的消息主题</h4>
          <el-select v-model="bubbleStyleSelf" class="theme-select">
            <el-option label="默认主题" value="default" />
            <el-option label="自定义" value="custom" />
          </el-select>
          <div v-if="bubbleStyleSelf === 'custom'" class="color-pickers">
            <div class="color-item">
              <span>背景色</span>
              <el-color-picker v-model="customSelfColor[0]" show-alpha />
            </div>
            <div class="color-item">
              <span>文字色</span>
              <el-color-picker v-model="customSelfColor[1]" />
            </div>
          </div>
        </div>

        <div class="setting-group">
          <h4 class="group-title">音频控制</h4>
          <audio :src="testAudio" controls class="audio-player" />
        </div>
      </div>
    </el-drawer>

    <!-- Playlist Drawer -->
    <el-drawer
        v-model="drawer"
        title="音频播放列表"
        direction="rtl"
        size="400px"
        class="playlist-drawer"
    >
      <div class="playlist-content">
        <div v-if="totalAudioItems === 0" class="empty-playlist">
          <el-icon class="empty-icon"><List /></el-icon>
          <span>暂无播放项目</span>
        </div>

        <div v-else class="playlist-items">
          <!-- Currently Playing -->
          <div v-if="currentAudio" class="playlist-item current">
            <div class="item-header">
              <span class="item-index">正在播放</span>
              <div class="item-controls">
                <el-button
                    size="small"
                    :type="paused ? 'success' : 'warning'"
                    @click="paused ? audioRef.play() : audioRef.pause()"
                >
                  <el-icon>
                    <VideoPlay v-if="paused" />
                    <VideoPause v-else />
                  </el-icon>
                </el-button>
              </div>
            </div>
            <div class="item-content">
              {{ currentAudio.message.content }}
            </div>
            <div class="item-status playing">
              {{ paused ? '已暂停' : '正在播放' }}
            </div>
          </div>

          <!-- Ready Queue -->
          <div
              v-for="(item, index) in AudioReadyQueue"
              :key="`ready-${index}`"
              class="playlist-item ready"
          >
            <div class="item-header">
              <span class="item-index">{{ index + 1 + (currentAudio ? 1 : 0) }}</span>
              <div class="item-controls">
                <el-button
                    size="small"
                    type="danger"
                    @click="AudioReadyQueue.splice(index, 1)"
                >
                  <el-icon><Close /></el-icon>
                </el-button>
              </div>
            </div>
            <div class="item-content">
              {{ item.message.content }}
            </div>
            <div class="item-status ready">就绪</div>
          </div>

          <!-- Processing Queue -->
          <div
              v-for="(item, index) in AudioMessageQueue"
              :key="`processing-${index}`"
              class="playlist-item processing"
          >
            <div class="item-header">
              <span class="item-index">{{ index + 1 + (currentAudio ? 1 : 0) + AudioReadyQueue.length }}</span>
              <div class="item-controls">
                <el-button
                    size="small"
                    type="danger"
                    @click="AudioMessageQueue.splice(index, 1)"
                >
                  <el-icon><Close /></el-icon>
                </el-button>
              </div>
            </div>
            <div class="item-content">
              {{ item.content }}
            </div>
            <div class="item-status processing">处理中</div>
          </div>
        </div>
      </div>
    </el-drawer>
  </div>
</template>

<style lang="scss" scoped>
@import url('https://fonts.googleapis.com/css2?family=Noto+Sans+SC:wght@300;400;500;700&display=swap');

.interview-container {
  font-family: 'Noto Sans SC', sans-serif;
  height: 100vh;
  padding: 20px;
  background: linear-gradient(135deg, #f5f7fa 0%, #c3cfe2 100%);
  opacity: 0;
  transform: translateY(10px);
  transition: all 0.5s cubic-bezier(0.4, 0, 0.2, 1);

  &.fade-in {
    opacity: 1;
    transform: translateY(0);
  }
}

.floating-actions {
  position: fixed;
  left: 20px;
  top: 50%;
  transform: translateY(-50%);
  display: flex;
  flex-direction: column;
  gap: 12px;
  z-index: 1000;

  .action-btn {
    width: 48px;
    height: 48px;
    box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
    transition: all 0.3s ease;
    position: relative;

    &:hover {
      transform: translateX(5px);
      box-shadow: 0 6px 20px rgba(0, 0, 0, 0.25);
    }

    .audio-badge {
      position: absolute;
      top: -8px;
      right: -8px;
    }
  }
}

.main-interface {
  display: flex;
  gap: 20px;
  height: calc(100vh - 40px);
  max-width: 1400px;
  margin: 0 auto;
}

.chat-section {
  flex: 1;
  display: flex;
  flex-direction: column;
  background: white;
  border-radius: 12px;
  box-shadow: 0 4px 20px rgba(0, 0, 0, 0.1);
  overflow: hidden;

  .status-header {
    display: flex;
    justify-content: space-between;
    align-items: center;
    padding: 16px 20px;
    background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
    color: white;

    .status-indicator {
      display: flex;
      align-items: center;
      gap: 10px;

      .status-dot {
        width: 12px;
        height: 12px;
        border-radius: 50%;
        animation: pulse 2s infinite;
      }

      .status-text {
        font-weight: 600;
        font-size: 16px;
      }
    }

    .header-actions {
      .el-button {
        background: rgba(255, 255, 255, 0.2);
        border: 1px solid rgba(255, 255, 255, 0.3);
        color: white;

        &:hover {
          background: rgba(255, 255, 255, 0.3);
        }
      }
    }
  }

  .chat-container {
    flex: 1;
    overflow-y: auto;
    padding: 20px;
    background: #f8fafc;
    scroll-behavior: smooth;

    .chat-message {
      margin-bottom: 16px;
      animation: slideIn 0.3s ease-out;
    }
  }
}

.control-panel {
  width: 380px;
  display: flex;
  flex-direction: column;
  gap: 16px;

  .video-section {
    background: white;
    border-radius: 12px;
    padding: 16px;
    box-shadow: 0 2px 12px rgba(0, 0, 0, 0.08);

    .video-header {
      display: flex;
      justify-content: space-between;
      align-items: center;
      margin-bottom: 12px;

      .video-title {
        font-weight: 600;
        color: #374151;
      }

      .camera-toggle {
        display: flex;
        align-items: center;
        gap: 4px;
      }
    }

    .video-wrapper {
      position: relative;
      border-radius: 8px;
      overflow: hidden;
      background: #000;
      height: 140px;

      .video-preview {
        width: 100%;
        height: 100%;
        object-fit: cover;

        &.inactive {
          filter: brightness(0.3);
        }
      }

      .video-overlay {
        position: absolute;
        top: 50%;
        left: 50%;
        transform: translate(-50%, -50%);
        display: flex;
        flex-direction: column;
        align-items: center;
        gap: 8px;
        color: white;

        .overlay-icon {
          font-size: 24px;
        }

        span {
          font-size: 14px;
        }
      }
    }
  }

  .input-section {
    background: white;
    border-radius: 12px;
    padding: 16px;
    box-shadow: 0 2px 12px rgba(0, 0, 0, 0.08);
    flex: 1;

    .input-header {
      display: flex;
      justify-content: space-between;
      align-items: center;
      margin-bottom: 12px;

      .input-title {
        font-weight: 600;
        color: #374151;
      }

      .record-btn {
        display: flex;
        align-items: center;
        gap: 4px;
        font-size: 12px;
      }
    }

    .message-input {
      margin-bottom: 12px;

      :deep(.el-textarea__inner) {
        border-radius: 8px;
        border: 2px solid #e5e7eb;
        transition: all 0.3s ease;

        &:focus {
          border-color: #667eea;
          box-shadow: 0 0 0 3px rgba(102, 126, 234, 0.1);
        }
      }
    }

    .input-controls {
      display: flex;
      gap: 8px;

      .send-btn,
      .finish-btn {
        flex: 1;
        display: flex;
        align-items: center;
        justify-content: center;
        gap: 6px;
        padding: 10px;
        font-weight: 500;
        border-radius: 8px;
        transition: all 0.3s ease;

        &:hover:not(:disabled) {
          transform: translateY(-1px);
          box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
        }
      }
    }
  }

  .audio-visualizer {
    background: white;
    border-radius: 12px;
    padding: 16px;
    box-shadow: 0 2px 12px rgba(0, 0, 0, 0.08);
    height: 80px;

    .visualizer-component {
      width: 100%;
      height: 100%;
      border-radius: 8px;
      overflow: hidden;
    }
  }
}

.settings-drawer,
.playlist-drawer {
  :deep(.el-drawer__header) {
    background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
    color: white;
    margin-bottom: 0;
    padding: 20px;
  }

  :deep(.el-drawer__body) {
    padding: 0;
  }
}

.settings-content {
  padding: 20px;

  .setting-group {
    margin-bottom: 24px;

    .group-title {
      font-size: 16px;
      font-weight: 600;
      color: #374151;
      margin: 0 0 12px;
    }

    .theme-select {
      width: 100%;
      margin-bottom: 12px;
    }

    .color-pickers {
      display: flex;
      flex-direction: column;
      gap: 8px;

      .color-item {
        display: flex;
        justify-content: space-between;
        align-items: center;
        padding: 8px 12px;
        background: #f8fafc;
        border-radius: 6px;

        span {
          font-size: 14px;
          color: #6b7280;
        }
      }
    }

    .audio-player {
      width: 100%;
      border-radius: 6px;
    }
  }
}

.playlist-content {
  .empty-playlist {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    padding: 60px 20px;
    color: #9ca3af;

    .empty-icon {
      font-size: 48px;
      margin-bottom: 12px;
    }

    span {
      font-size: 16px;
    }
  }

  .playlist-items {
    padding: 20px;

    .playlist-item {
      background: white;
      border-radius: 8px;
      padding: 16px;
      margin-bottom: 12px;
      box-shadow: 0 2px 8px rgba(0, 0, 0, 0.06);
      border-left: 4px solid;

      &.current {
        border-left-color: #409eff;
        background: linear-gradient(135deg, #e3f2fd 0%, #bbdefb 100%);
      }

      &.ready {
        border-left-color: #67c23a;
      }

      &.processing {
        border-left-color: #e6a23c;
      }

      .item-header {
        display: flex;
        justify-content: space-between;
        align-items: center;
        margin-bottom: 8px;

        .item-index {
          font-size: 12px;
          font-weight: 600;
          color: #6b7280;
        }
      }

      .item-content {
        font-size: 14px;
        color: #374151;
        line-height: 1.5;
        margin-bottom: 8px;
        display: -webkit-box;
        -webkit-box-orient: vertical;
        -webkit-line-clamp: 2;
        overflow: hidden;
      }

      .item-status {
        font-size: 12px;
        font-weight: 500;
        padding: 2px 8px;
        border-radius: 4px;
        display: inline-block;

        &.playing {
          background: #e3f2fd;
          color: #1976d2;
        }

        &.ready {
          background: #e8f5e8;
          color: #2e7d32;
        }

        &.processing {
          background: #fff3e0;
          color: #f57c00;
        }
      }
    }
  }
}

@keyframes pulse {
  0%, 100% {
    opacity: 1;
  }
  50% {
    opacity: 0.5;
  }
}

@keyframes slideIn {
  from {
    opacity: 0;
    transform: translateY(10px);
  }
  to {
    opacity: 1;
    transform: translateY(0);
  }
}

// Responsive Design
@media (max-width: 1200px) {
  .main-interface {
    flex-direction: column;
    height: auto;
  }

  .control-panel {
    width: 100%;
    flex-direction: row;
    flex-wrap: wrap;

    .video-section,
    .input-section,
    .audio-visualizer {
      flex: 1;
      min-width: 300px;
    }
  }

  .floating-actions {
    position: relative;
    left: auto;
    top: auto;
    transform: none;
    flex-direction: row;
    justify-content: center;
    margin-bottom: 20px;
  }
}

@media (max-width: 768px) {
  .interview-container {
    padding: 10px;
  }

  .main-interface {
    gap: 10px;
  }

  .control-panel {
    flex-direction: column;

    .video-section,
    .input-section,
    .audio-visualizer {
      min-width: auto;
    }
  }

  .floating-actions {
    .action-btn {
      width: 40px;
      height: 40px;
    }
  }
}
</style>